package sharewithus.solrclient;

import java.io.IOException;
import java.util.Arrays;
import java.util.Collection;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;

import org.apache.solr.client.solrj.SolrQuery;
import org.apache.solr.client.solrj.SolrServer;
import org.apache.solr.client.solrj.SolrServerException;
import org.apache.solr.client.solrj.request.AbstractUpdateRequest;
import org.apache.solr.client.solrj.request.UpdateRequest;
import org.apache.solr.client.solrj.response.QueryResponse;
import org.apache.solr.client.solrj.response.UpdateResponse;
import org.apache.solr.common.SolrDocument;
import org.apache.solr.common.SolrDocumentList;
import org.apache.solr.common.SolrInputDocument;
import org.apache.solr.common.params.SolrParams;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import sharewithus.solrclient.support.BeanDocConverter;
import sharewithus.solrclient.support.OrderBy;
import sharewithus.solrclient.support.Pagination;

/**
 * Title:SolrClient Description:solr客户端操作类
 * 
 * @Create_by:Terry
 * @Create_date:2012-5-24
 * @Last_Edit_By:
 * @Edit_Description
 * @version:ShareWithUs 1.0
 * 
 */
public class SolrClientImpl<T> implements SolrClient<T> {

	private static final Logger logger = LoggerFactory
			.getLogger(SolrClientImpl.class);

	private static SolrClientImpl<?> _instance = null;

	private SolrServer server;
	private Class<T> beanCls;

	private SolrClientImpl(SolrServer server, Class<T> beanCls) {
		this.server = server;
		this.beanCls = beanCls;
	}

	
	/**
	 * 工厂方法,构造单例Client
	 * @param server SolrServer实例
	 * @param beanCls 实体class,注意此class不能是抽象类或者接口class
	 * @return
	 */
	@SuppressWarnings({ "unchecked", "rawtypes" })
	public static SolrClientImpl getInstance(SolrServer server, Class<?> beanCls) {
		if (_instance == null) {
			synchronized (logger) {
				_instance = new SolrClientImpl(server, beanCls);
			}
		}
		return _instance;
	}

	private int getStart(int pageNo, int pageSize) {
		return (pageNo - 1) * pageSize;
	}

	protected QueryResponse queryByParams(SolrParams params) {
		QueryResponse response = null;
		try {
			response = server.query(params);
		} catch (SolrServerException e) {
			logger.error(e.getMessage());
			return null;
		}
		return response;
	}

	public Pagination<T> query(String queryString, int pageNo, int pageSize,
			OrderBy orderBy) {
		if (queryString == null || queryString.isEmpty())
			throw new IllegalArgumentException();
		SolrQuery query = new SolrQuery();
		query.setQuery(queryString).setStart(getStart(pageNo, pageSize))
				.setRows(pageSize);
		if (orderBy != null && orderBy.validate()) {
			for (String f : orderBy.getFields()) {
				query.addSortField(f, orderBy.getOrder());
			}
		}
		QueryResponse response = queryByParams(query);
		List<T> list = (List<T>) BeanDocConverter.docs2beans(
				response.getResults(), this.beanCls);
		int totalCount = Long.valueOf(response.getResults().getNumFound())
				.intValue();
		return new Pagination<T>(pageNo, pageSize, totalCount, list);
	}

	public Pagination<T> query(SolrQuery query, int pageNo, int pageSize,
			OrderBy orderBy) {
		query.setStart(getStart(pageNo, pageSize)).setRows(pageSize);
		if (orderBy != null && orderBy.validate()) {
			for (String f : orderBy.getFields()) {
				query.addSortField(f, orderBy.getOrder());
			}
		}
		QueryResponse response = queryByParams(query);
		List<T> list = (List<T>) BeanDocConverter.docs2beans(
				response.getResults(), this.beanCls);
		int totalCount = Long.valueOf(response.getResults().getNumFound())
				.intValue();
		return new Pagination<T>(pageNo, pageSize, totalCount, list);
	}

	public boolean update(Map<String, Object> valueMap, SolrQuery query) {
		try {
			System.out.println(query.toString());
			QueryResponse qrsp = server.query(query);
			SolrDocumentList list = qrsp.getResults();
			List<SolrInputDocument> inputDocs = new LinkedList<SolrInputDocument>();
			for (SolrDocument doc : list) {
				SolrInputDocument inputdoc = BeanDocConverter.doc2InputDoc(doc);
				for (Map.Entry<String, Object> entry : valueMap.entrySet()) {
					inputdoc.setField(entry.getKey(), entry.getValue());
				}
				inputDocs.add(inputdoc);
			}
			UpdateRequest updateRequest = new UpdateRequest();
			updateRequest.setAction(AbstractUpdateRequest.ACTION.COMMIT, false,
					false);
			updateRequest.add(inputDocs);
			UpdateResponse urp = updateRequest.process(server);
			return urp.getStatus() == 0;
		} catch (Exception e) {
			logger.error(e.getMessage());
		}
		return false;
	}

	@Override
	public boolean update(Map<String, Object> valueMap, String queryString) {
		SolrQuery query = new SolrQuery(queryString);
		return update(valueMap, query);
	}

	public boolean update(Map<String, Object> valueMap, String... ids) {
		if (ids == null || ids.length == 0 || valueMap == null)
			throw new IllegalArgumentException();
		StringBuffer q = new StringBuffer();
		q.append(SolrClient.SOLR_SCHEMA_KEY_NAME + ":(");
		for (String id : ids) {
			q.append(" ").append(id);
		}
		q.append(" )");
		SolrQuery query = new SolrQuery(q.toString());
		query.setStart(0).setRows(ids.length);
		return update(valueMap, query);
	}

	public boolean commitBean(T bean) {
		try {
			server.add(BeanDocConverter.bean2InputDoc(bean));
			UpdateResponse rsp = server.commit(false, false);
			logger.info("Commit bean to solr server");
			return rsp.getStatus() == 0;
		} catch (Exception e) {
			logger.error(e.getMessage());
		}
		return false;
	}

	public boolean commitBeans(Collection<T> beans) {
		try {
			server.add(BeanDocConverter.beans2Inputdocs(beans));
			UpdateResponse rsp = server.commit(false, false);
			logger.info("Commit beans : " + beans.size() + " to solr server");
			return rsp.getStatus() == 0;
		} catch (Exception e) {
			logger.error(e.getMessage());
		}
		return false;
	}

	public boolean deleteById(String... ids) {
		try {
			List<String> list = Arrays.asList(ids);
			server.deleteById(list);
			UpdateResponse rsp = server.commit(false, false);
			return rsp.getStatus() == 0;
		} catch (Exception e) {
			logger.error(e.getMessage());
		}
		return false;
	}

	public boolean deleteByQuery(String queryString) {
		try {
			server.deleteByQuery(queryString);
			UpdateResponse rsp = server.commit(false, false);
			return rsp.getStatus() == 0;
		} catch (Exception e) {
			logger.error(e.getMessage());
		}
		return false;
	}

	public boolean deleteByQuery(SolrQuery query) {
		return deleteByQuery(query.toString());
	}

	public boolean optimize() {
		try {
			long now = System.currentTimeMillis();
			server.optimize(true, false);
			return server.optimize(false, false).getStatus()== 0;
		} catch (SolrServerException e) {
			logger.error(e.getMessage());
		} catch (IOException e) {
			logger.error(e.getMessage());
		}
		return false;
	}

}
